/**
 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

// Example of reading/writing an external serial flash using the PL022 SPI interface

#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/binary_info.h"
#include "hardware/spi.h"

#include "wizchip_conf.h"
#include "w5100s.h"
#include "bsp_spi.h"
#include "dns.h"
#include "dhcp.h"
#include "socket.h"

#define ETHERNET_BUF_MAX_SIZE (1024 * 2)
#define DNS_RET_FAIL 0
#define DNS_RET_SUCCESS 1
#define DNS_RETRY 3 /* 3 times */
#define SOCKET_ID 0
#define ETHERNET_BUF_MAX_SIZE (1024 * 2)
#define DHCP_RETRY_COUNT 5 // DHCP retry times

wiz_NetInfo net_info = {
    .mac = {0x00, 0x08, 0xdc, 0x16, 0xed, 0x2e}, // Define MAC variables
    .ip = {192, 168, 1, 10},                     // Define IP variables
    .sn = {255, 255, 255, 0},                    // Define subnet variables
    .gw = {192, 168, 1, 1},                      // Define gateway variables
    .dns = {8, 8, 8, 8},                         // Define DNS  variables
    .dhcp = NETINFO_DHCP};                       // Define the DNCP mode
wiz_NetInfo get_info;
static uint8_t ethernet_buf[ETHERNET_BUF_MAX_SIZE] = {
    0,
};
uint8_t Domain_name[] = "www.baidu.com"; // The domain name that needs to be resolved
uint8_t Domain_IP[4] = {
    0,
};
static uint8_t dhcp_get_ip_flag = 0; // Define the DHCP acquisition flag

/*
    @brief Callback processing after triggering the timer.
    @param Timer struct.
    @return True.
 */
bool repeating_timer_callback_DNS(struct repeating_timer *t);

/**
 * @brief   Timer callback processing function, used for dhcp timing processing
 * @param   repeating :Timer structure
 * @return  bool
 */
bool repeating_timer_callback_DHCP(struct repeating_timer *t);

/**
 * @brief   Initialization of chip network information
 * @param   conf_info :Static configuration information
 * @return  none
 */
void network_init(wiz_NetInfo *conf_info);

int main()
{
    struct repeating_timer timer;  // Define the timer structure
    struct repeating_timer timer1; // Define the timer structure
    uint8_t dns_retry_cnt = 0;     // Number of parsings
    uint8_t dns_ok = 0;            // Parse success Peugeot

    /*mcu init*/
    stdio_init_all();     // Initialize the main control periphera
    wizchip_initialize(); // spi initialization
    wizchip_setnetinfo(&net_info); // Configure once first
    
    /*dhcp init*/
    DHCP_init(SOCKET_ID, ethernet_buf);                                        // DHCP initialization
    add_repeating_timer_ms(1000, repeating_timer_callback_DHCP, NULL, &timer); // Add DHCP 1s Tick Timer handler

    printf("wiznet chip dns client example.\r\n");
    network_init(&net_info);              // Configuring Network Information
    print_network_information(&get_info); // Read back the configuration information and print it

    /*dns init*/
    DNS_init(0, ethernet_buf);                                                 // DNS client init
    add_repeating_timer_ms(1000, repeating_timer_callback_DNS, NULL, &timer1); // Add  DNS 1s Tick Timer handler
    printf("\r\n===== DNS Client Example =====\r\n");
    printf("> Example Domain Name : %s\r\n", Domain_name);

    while (true)
    {

        if ((dns_ok == 0) && (dns_retry_cnt < DNS_RETRY)) // Determine whether the parsing is successful or whether the parsing exceeds the number of times
        {
            switch (DNS_run(net_info.dns, Domain_name, Domain_IP)) // Read the DNS_run return value
            {
            case DNS_RET_FAIL: // The DNS domain name is successfully resolved
            {
                dns_retry_cnt++;
                printf("> DNS Failed\r\n");
            }
            break;
            case DNS_RET_SUCCESS: // DNS domain name resolution failed
            {
                dns_ok = 1;
                printf("> Translated %s to %d.%d.%d.%d\r\n", Domain_name, Domain_IP[0], Domain_IP[1], Domain_IP[2], Domain_IP[3]);
            }
            break;
            }
        }
    }
}

/* Timer */
bool repeating_timer_callback_DNS(struct repeating_timer *t)
{
    DNS_time_handler(); // DNS 1s Tick Timer handler
    return true;
}

bool repeating_timer_callback_DHCP(struct repeating_timer *t)
{
    DHCP_time_handler(); // DHCP 1s Tick Timer handler
    return true;
}

void network_init(wiz_NetInfo *conf_info)
{
    int count = 0;
    int dhcp_state = 0;
    int breakout_flag = 0;

    if (conf_info->dhcp == NETINFO_DHCP)
    {
        while (true)
        {
            dhcp_state = DHCP_run(); // Do the DHCP client

            switch (dhcp_state)
            {
            case DHCP_IP_LEASED: // DHCP obtained the IP successfully
                if (dhcp_get_ip_flag == 0)
                {
                    dhcp_get_ip_flag = 1;

                    getSHAR(get_info.mac);
                    getIPfromDHCP(get_info.ip);
                    getGWfromDHCP(get_info.gw);
                    getSNfromDHCP(get_info.sn);
                    getDNSfromDHCP(get_info.dns);
                    get_info.dhcp = NETINFO_DHCP;
                    breakout_flag = 1;
                    /* Network initialize */
                    network_initialize(get_info); // apply from DHCP

                    printf(" DHCP leased time : %ld seconds\n", getDHCPLeasetime());
                }
                break;
            case DHCP_FAILED: // DHCP failed to obtain IP
                count++;
                if (count <= DHCP_RETRY_COUNT) // If the number of times is less than or equal to the maximum number of times, try again
                {
                    printf(" DHCP timeout occurred and retry %d \r\n", count);
                }
                else if (count > DHCP_RETRY_COUNT) // If the number of times is greater than DHCP fails
                {
                    printf(" DHCP failed \r\n");
                    DHCP_stop(); // Stop processing DHCP protocol
                    breakout_flag = 1;
                    net_info.dhcp = NETINFO_STATIC;
                    wizchip_setnetinfo(&net_info); // Write configuration information
                }
            }
            if (breakout_flag == 1) // Get out of the loop
            {
                printf("config succ\r\n");
                break;
            }
        }
    }
    else
    {
        wizchip_setnetinfo(&net_info); // Configuring Network Information
    }
}
